Unity渲染管线(二) 深度值相关

前言

咕咕咕了半个月。。

这次从通过 LWRP 的 Render Features 实现遮挡显示轮廓效果来让大家对渲染管线有一个大致的轮廓。

参考链接

介绍

效果:

是一个当固定层级物体被遮挡后显示轮廓的功能,使用 Shader 也可以完成,使用 LWRP 的 Render Features 的话完成的更直观一些。

步骤


  • 安装 LWRP
    此次运行版本需要 2019 四月份以后的版本,我选择的是 2019.1.9f1,在创建项目时直接创建 LWRP项目, LWRP 的版本要求是 5.7 以上,在 Windows—>Package Manager 中下载。

  • 勾选 pre
    需要勾选 show preview package 才能显示预览版的功能包。



  • 分别创建 管线资源 和 前向渲染器



  • 在 Project Setting 中 将创建好的渲染管线拖入其中,把 LWRP资源的 渲染模式改为 Custom 并把创建的 前向渲染器资源 拖到 LWRP 资源中。


  • 新建一个场景,放置几个资源,会发现新建的 3D GameObjcet 使用了不同的 默认 Shader,这是由于更换了渲染管线,具体的 默认Shader 也随之改变了。



  • 在 前向渲染器 中添加如图所示的一个 RendererFeature,其中的材质是选择的一个 Unity 自带的默认材质,并把如图后面两个资源改为 Character 层级,得到的效果就像第二幅图一样,有个地方不尽人意,就是同为 Character 层级,也出现了遮挡后显示轮廓的效果。


  • 如图所示,将 ForwardRender 再新建一个 RenderFeatrues,并把 前向渲染器的 默认层级遮罩 取消掉勾选 Character 层级,就大致可以得到文章开头的效果了。



  • 存在一个问题,就是同层级的物体之间还是可能会有出现遮挡显示轮廓的效果,但我们可以把他们当做一体选择一个只有颜色没有轮廓的 材质 来做遮挡显示。

讲解

前面的创建与设置过程不做讲解,主要是一些默认操作,很多参数也是保持了默认。主要是对效果实现的讲解。

原理科普

  • 渲染队列

    场景中有一个一个的 GameObject(下面简称为 GO),对于这些 GO,我们要根据其身上的材质进行渲染,这里有一个问题,即先渲染哪一个后渲染哪一个,不要以为渲染顺序不会影响最终效果,渲染顺序透明度实现上会产生很大的影响。

    而这里使用 Rendere Feature 强行改变了渲染队列,以及后续渲染采用的 材质。

  • 深度值

    即 Z。摄像机在游戏中相当于我们的眼睛,我们只能看到眼睛最前面的片元A,而看不到挡在后面的片元B,就是说B离我们远,抽象到渲染中就是 Z 值比较大,这样的话我们可以在渲染物体时判断其 Z值 是否大于当前存储的 Z值,如果大于就不渲染,如果小于就渲染,并把存储的 Z值 更新。

    深度测试通过,深度写入开启:写入深度缓冲区,写入颜色缓冲区
    深度测试通过,深度写入关闭:不写深度缓冲区,写入颜色缓冲区
    深度测试失败,深度写入开启:不写深度缓冲区,不写颜色缓冲区
    深度测试失败,深度写入关闭:不写深度缓冲区,不写颜色缓冲区

  • ZTest 深度值测试,通过测试才进行渲染
    ZTest Less:深度小于当前缓存则通过
    ZTest Greater:深度大于当前缓存则通过
    ZTest LEqual/on:深度小于等于当前缓存则通过
    ZTest GEqual:深度大于等于当前缓存则通过
    ZTest Equal:深度等于当前缓存则通过
    ZTest NotEqual:深度不等于当前缓存则通过
    ZTest Always/off:不论如何都通过

  • ZWrite on/off 深度值写入,当渲染通过是是否写入新的深度值

    在 Renderer Feature 中,也是将这个深度测试与深度写入单独抽出来,在外部进行更改。

面板分析


让我们分析一下这个面板

  • Deafult Layer Mask,这个分层级进行渲染,如果我们选择 Nothing,那么所有的层级都不会被渲染
  • Overrids,这个是指覆盖,即通过筛选之后得到需要进行操作的部分进行覆盖绘制,Stencil 这里没有用到,后续会进行讲解。
  • Renderer Features
    • Name,Renderer Features 的名字
    • Event,指在什么时候进行操作
    • Fliters
      • Queue,队列,Opaque 指筛选不透明的队列
      • Layer Mask,筛选 Character 层级
      • Shader Passes,具体使用到的 Shader Pass
    • Overrieds 覆盖绘制
      • Material 覆盖绘制的材质
      • Depth 深度
        • 是否把深度写入
        • 是否测试深度,这里选择深度大于渲染过程中的深度值才进行渲染,即当物体深度值比较大被其他物体遮挡住的时候被渲染,也就是只有被遮挡的部分才会被渲染
        • 其余待后续测试

效果实现


实际上我们分为三个步骤

  • 对遮挡部分进行渲染,然后发现被同一层级遮挡的部分也被渲染了;

  • 然后取消一开始对 Character 层级的渲染,即在 前向渲染器中 的 Deafult Layer Mask 取消对 Character 的勾选;

  • 然后发现不被遮挡的部分不会被渲染,这个时候我们选择正常根据深度值缓存来渲染出不被遮挡的部分。

总结

其实使用 Shader 我们一样可以实现相同的效果,甚至在原理上也差不多,但是使用编写的方式相当于改变了 Shader 效果本身,使用 RenderFeatures 相当于在外部来更改其一些参数来使用,把 Shader、材质当做对象在不同的条件下调用可以说是 渲染管线 的一部分责任。

0%